package com.zgc.view.controller;

import com.fx.spring.annotation.ControllerFX;
import com.fx.spring.controller.AbstractController;
import com.jfoenix.controls.*;
import com.zgc.cache.ConnectionInfoCache;
import com.zgc.cache.CuratorClientCache;
import com.zgc.cache.TreeItemCache;
import com.zgc.constant.ZkConstant;
import com.zgc.util.CuratorZkUtil;
import com.zgc.view.cell.ZkNodeTreeViewCell;
import com.zgc.view.common.AlertCtrl;
import com.zgc.view.common.PopupCtrl;
import com.zgc.view.svg.SvgIconEnum;
import com.zgc.zkinfo.ZkConnectionInfo;
import com.zgc.zkinfo.ZkNodeInfo;
import javafx.application.Platform;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.When;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@ControllerFX(fxmlURL = "/view/fxml/InformationTab.fxml")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class InformationTabCtrl extends AbstractController<Tab> {

    @FXML
    private Tab informationTab;
    @FXML
    private SplitPane zkInformation;
    @FXML
    private VBox treeRootVbox;
    @FXML
    private JFXListView<TextFlow> searchResultListView;
    @FXML
    private JFXTreeView<ZkNodeInfo> zkNodeTreeView;
    @FXML
    private TreeItem<ZkNodeInfo> rootTreeItem;
    @FXML
    private JFXTextField searchField;
    @FXML
    private JFXTextField hostTextField;
    @FXML
    private JFXTextField currentPathTextField;
    @FXML
    private JFXListView<String> aclListView;
    @FXML
    private JFXTextField statPzxid;
    @FXML
    private JFXTextField statCzxid;
    @FXML
    private JFXTextField statMzxid;
    @FXML
    private JFXTextField statCtime;
    @FXML
    private JFXTextField statMtime;
    @FXML
    private JFXTextField statVersion;
    @FXML
    private JFXTextField statCversion;
    @FXML
    private JFXTextField statAversion;
    @FXML
    private JFXTextField statDataLength;
    @FXML
    private JFXTextField statNumChildren;
    @FXML
    private JFXTextField statEphemeralOwner;
    @FXML
    private JFXComboBox<String> dataType;
    @FXML
    private JFXComboBox<String> dataCharset;
    @FXML
    private TextArea dataTextArea;
    @FXML
    private JFXButton editDataButton;
    @FXML
    private JFXButton saveDataButton;
    @FXML
    private JFXButton cancelDataButton;
    @FXML
    private JFXButton copyDataButton;
    @FXML
    private JFXButton refreshDataButton;
    @FXML
    private JFXButton editAclButton;
    @FXML
    private JFXButton saveAclButton;
    @FXML
    private JFXButton copyAclButton;
    @FXML
    private JFXButton refreshAclButton;
    @FXML
    private JFXButton editStatButton;
    @FXML
    private JFXButton cancelStatButton;
    @FXML
    private JFXButton saveStatButton;
    @FXML
    private JFXButton copyStatButton;
    @FXML
    private JFXButton refreshStatButton;
    @FXML
    private Text statPzxidText;
    @FXML
    private Text statCzxidText;
    @FXML
    private Text statMzxidText;
    @FXML
    private Text statCtimeText;
    @FXML
    private Text statMtimeText;
    @FXML
    private Text statVersionText;
    @FXML
    private Text statCversionText;
    @FXML
    private Text statAversionText;
    @FXML
    private Text statDataLengthText;
    @FXML
    private Text statNumChildrenText;
    @FXML
    private Text statEphemeralOwnerText;


    @Autowired
    private AlertCtrl alertCtrl;

    @Autowired
    private InformationTableCtrl informationTableCtrl;

    @Autowired
    private PopupCtrl popupCtrl;


    private final SimpleBooleanProperty dataDisableProperty = new SimpleBooleanProperty(false);
    private final SimpleBooleanProperty statDisableProperty = new SimpleBooleanProperty(false);
    private final SimpleBooleanProperty aclDisableProperty = new SimpleBooleanProperty(false);
    //粘贴板
    private final Clipboard clipboard = Clipboard.getSystemClipboard();


    @Override
    public void initialize(URL location, ResourceBundle resources) {
        logger.debug("[{}]初始化完成", location);
        zkInformation.setDividerPosition(0, 0.3);
        initContextMenu();
        initAclListView();
        initTreeView();
        initSearchNode();
        initZkAclNode();
        initZkStatNode();
        initZkDataNode();
    }


    @FXML
    private void expandedTree(ActionEvent actionEvent) {
        expandedOrCloseTree(rootTreeItem, true);
    }

    @FXML
    private void closeTree(ActionEvent actionEvent) {
        expandedOrCloseTree(rootTreeItem, false);
    }

    @FXML
    private void editAcl(ActionEvent actionEvent) {
        alertCtrl.setMessageAndShow("编辑ACL（待开发）");
    }

    @FXML
    private void saveAcl(ActionEvent actionEvent) {
        alertCtrl.setMessageAndShow("保存ACL（待开发）");
    }

    @FXML
    private void copyAcl(ActionEvent actionEvent) {
        alertCtrl.setMessageAndShow("复制ACL（待开发）");
    }

    @FXML
    private void refreshAcl(ActionEvent actionEvent) {
        alertCtrl.setMessageAndShow("刷新ACL（待开发）");
    }


    @FXML
    private void editStat(ActionEvent actionEvent) {
        statDisableProperty.set(true);
    }

    @FXML
    private void cancelStat(ActionEvent actionEvent) {
        statDisableProperty.set(false);
        ZkNodeInfo currentZkNodeInfo = getCurrentTreeItem();
        if (currentZkNodeInfo != null) {
            setZkStat(currentZkNodeInfo);
        }
    }

    @FXML
    private void saveStat(ActionEvent actionEvent) {
        statDisableProperty.set(false);
        editStatButton.requestFocus();
    }

    @FXML
    private void copyStat(ActionEvent actionEvent) {
        StringJoiner statString = new StringJoiner("\n");
        statString.add(statPzxidText.getText() + statPzxid.getText());
        statString.add(statCzxidText.getText() + statCzxid.getText());
        statString.add(statMzxidText.getText() + statMzxid.getText());
        statString.add(statCtimeText.getText() + statCtime.getText());
        statString.add(statMtimeText.getText() + statMtime.getText());
        statString.add(statVersionText.getText() + statVersion.getText());
        statString.add(statCversionText.getText() + statCversion.getText());
        statString.add(statAversionText.getText() + statAversion.getText());
        statString.add(statDataLengthText.getText() + statDataLength.getText());
        statString.add(statNumChildrenText.getText() + statNumChildren.getText());
        statString.add(statEphemeralOwnerText.getText() + statEphemeralOwner.getText());
        ClipboardContent clipboardContent = new ClipboardContent();
        clipboardContent.putString(statString.toString());
        clipboard.setContent(clipboardContent);
        popupCtrl.enqueueRoot("复制成功", clipboardContent.getString());
    }

    @FXML
    private void refreshStat(ActionEvent actionEvent) {
        ZkNodeInfo currentZkNodeInfo = getCurrentTreeItem();
        if (currentZkNodeInfo != null) {
            CuratorFramework curatorClient = CuratorClientCache.getCuratorClient(informationTab.getId());
            CuratorZkUtil.getData(curatorClient, currentZkNodeInfo);
            setZkStat(currentZkNodeInfo);
        }
    }

    /** 编辑数据 */
    @FXML
    private void editData(ActionEvent actionEvent) {
        dataDisableProperty.set(true);
    }

    /** 取消 */
    @FXML
    private void cancelData(ActionEvent actionEvent) {
        dataDisableProperty.set(false);
        ZkNodeInfo currentZkNodeInfo = getCurrentTreeItem();
        if (currentZkNodeInfo != null) {
            setZkData(currentZkNodeInfo);
        }
    }

    /** 复制数据 */
    @FXML
    private void copyData(ActionEvent actionEvent) {
        String data = dataTextArea.getText();
        if (StringUtils.isEmpty(data)) {
            popupCtrl.enqueueRoot("没有数据", data);
        } else {
            ClipboardContent clipboardContent = new ClipboardContent();
            clipboardContent.putString(data);
            clipboard.setContent(clipboardContent);
            popupCtrl.enqueueRoot("复制成功", clipboardContent.getString());
        }
    }

    /** 保存数据 */
    @FXML
    private void saveData(ActionEvent actionEvent) {
        dataDisableProperty.set(false);
        editDataButton.requestFocus();
        String data = dataTextArea.getText();
        logger.debug("保存数据，[{}]", data);
        if (data != null) {
            try {
                CuratorFramework curatorClient = CuratorClientCache.getCuratorClient(informationTab.getId());
                String currentPath = currentPathTextField.getText();
                byte[] dataBytes = data.getBytes(dataCharset.getSelectionModel().getSelectedItem());
                CuratorZkUtil.setData(curatorClient, currentPath, dataBytes);
            } catch (UnsupportedEncodingException e) {
                logger.error("保存数据异常", e);
                popupCtrl.enqueueRoot("保存数据异常", e.getMessage());
            }
        }
    }

    /** 刷新数据 */
    @FXML
    private void refreshData(ActionEvent actionEvent) {
        ZkNodeInfo currentZkNodeInfo = getCurrentTreeItem();
        if (currentZkNodeInfo != null) {
            CuratorFramework curatorClient = CuratorClientCache.getCuratorClient(informationTab.getId());
            CuratorZkUtil.getData(curatorClient, currentZkNodeInfo);
            setZkData(currentZkNodeInfo);
        }
    }


    /**
     * 加载并设置标题
     *
     * @param connectionInfo 连接信息
     */
    public void setTextAndLoad(ZkConnectionInfo connectionInfo) {
        String zkId = connectionInfo.getId();
        informationTab.setId(zkId);
        informationTab.setText(connectionInfo.getHost());
        informationTab.setGraphic(connectionInfo.getStatIcon());
        hostTextField.setText(connectionInfo.getHost());
        refreshTreeView(connectionInfo);
    }

    private void initAclListView() {
        //失去焦点时清除选择的tree
        aclListView.focusedProperty().addListener((obv, ov, nv) -> {
            if (!nv) {
                aclListView.getSelectionModel().clearSelection();
            }
        });
    }


    // 初始化TreeView
    private void initTreeView() {
        zkNodeTreeView.setCellFactory(treeView -> new ZkNodeTreeViewCell(this, treeView));
        MultipleSelectionModel<TreeItem<ZkNodeInfo>> zkNodeTreeViewSelectionModel = zkNodeTreeView.getSelectionModel();
        //失去焦点时清除选择的tree
        zkNodeTreeView.focusedProperty().addListener((obv, ov, nv) -> {
            if (!nv) {
                zkNodeTreeViewSelectionModel.clearSelection();
            }
        });
        zkNodeTreeView.setOnMouseClicked(event -> {
            TreeItem<ZkNodeInfo> selectedZkNodeInfo = zkNodeTreeViewSelectionModel.getSelectedItem();
            if (selectedZkNodeInfo != null && MouseButton.PRIMARY.equals(event.getButton()) && event.getClickCount() == 2) {
                // 加载 table
                setZkInfo(ConnectionInfoCache.getConnectInfo(informationTab.getId()), selectedZkNodeInfo.getValue());
            }
        });
    }

    /**
     * 搜索框
     */
    private void initSearchNode() {
        // 初始化
        switchView(true);
        MultipleSelectionModel<TextFlow> searchResultModel = searchResultListView.getSelectionModel();
        MultipleSelectionModel<TreeItem<ZkNodeInfo>> zkNodeTreeViewModel = zkNodeTreeView.getSelectionModel();
        // 搜索
        searchField.textProperty().addListener((obv, ov, nv) -> {
            if (StringUtils.isEmpty(nv)) {
                switchView(true);
            } else {
                switchView(false);
                ObservableList<TextFlow> searchResultList = searchResultListView.getItems();
                searchResultList.clear();
                Map<String, TreeItem<ZkNodeInfo>> treeItemMap = TreeItemCache.get(informationTab.getId());
                List<TextFlow> searchResult = treeItemMap.keySet()
                        .stream()
                        .filter(item -> item.contains(nv))
                        .map(item -> {
                            TextFlow textFlow = new TextFlow();
                            textFlow.getChildren().addAll(highlightText(item, nv));
                            textFlow.setUserData(treeItemMap.get(item));
                            return textFlow;
                        }).collect(Collectors.toList());
                searchResultList.addAll(searchResult);
            }
        });
        //按上下键切换到ListView
        searchField.setOnKeyPressed(event -> {
            if (treeRootVbox.getChildren().contains(searchResultListView)) {
                switch (event.getCode()) {
                    case UP -> {
                        searchResultListView.requestFocus();
                        //选择第一个最后一个
                        searchResultModel.selectLast();
                    }
                    case DOWN -> {
                        searchResultListView.requestFocus();
                        //选择第一个
                        searchResultModel.selectFirst();
                    }
                    default -> {
                    }
                }
            }
        });

        //失去焦点时清除选择的tree
        searchResultListView.focusedProperty().addListener((obv, ov, nv) -> {
            if (!nv) {
                searchResultModel.clearSelection();
            }
        });
        //搜素结果跳转
        searchResultListView.setOnMouseClicked(event -> {
            if (MouseButton.PRIMARY.equals(event.getButton()) && event.getClickCount() == 2) {
                switchSearchResult(zkNodeTreeViewModel, searchResultModel);
            }
        });
        // 确定
        searchResultListView.setOnKeyPressed(event -> {
            if (KeyCode.ENTER.equals(event.getCode())) {
                switchSearchResult(zkNodeTreeViewModel, searchResultModel);
            }
        });
    }

    private void initZkAclNode() {
        /*saveAclButton.disableProperty().bind(new When(aclDisableProperty).then(false).otherwise(true));
        copyAclButton.disableProperty().bind(aclDisableProperty);
        refreshAclButton.disableProperty().bind(aclDisableProperty);*/
        editAclButton.setDisable(true);
        saveAclButton.setDisable(true);
        copyAclButton.setDisable(true);
        refreshAclButton.setDisable(true);
    }

    private void initZkStatNode() {
        editStatButton.disableProperty().bind(statDisableProperty);
        BooleanBinding disableBinding = new When(statDisableProperty).then(false).otherwise(true);
        cancelStatButton.disableProperty().bind(disableBinding);
        saveStatButton.disableProperty().bind(disableBinding);
        copyStatButton.disableProperty().bind(statDisableProperty);
        refreshStatButton.disableProperty().bind(statDisableProperty);
        statDisableProperty.addListener((obv, ov, nv) -> switchJFXTextFieldStyle(nv));
    }

    private void initZkDataNode() {
        dataType.getSelectionModel().selectFirst();
        dataCharset.getSelectionModel().selectFirst();
        dataTextArea.editableProperty().bind(dataDisableProperty);
        editDataButton.disableProperty().bind(dataDisableProperty);
        cancelDataButton.disableProperty().bind(new When(dataDisableProperty).then(false).otherwise(true));
        saveDataButton.disableProperty().bind(new When(dataDisableProperty).then(false).otherwise(true));
        copyDataButton.disableProperty().bind(dataDisableProperty);
        refreshDataButton.disableProperty().bind(dataDisableProperty);
        dataDisableProperty.addListener((obv, ov, nv) -> {
            if (nv) {
                dataTextArea.requestFocus();
            }
        });
    }

    /**
     * 刷新节点
     *
     * @param zkConnectionInfo 连接客户端
     */
    private void refreshTreeView(ZkConnectionInfo zkConnectionInfo) {
        logger.debug("连接信息{}", zkConnectionInfo);
        if (zkConnectionInfo != null) {
            rootTreeItem.setValue(new ZkNodeInfo(zkConnectionInfo.getId(), ZkConstant.ROOT_NODE, ZkConstant.ROOT_NODE));
            rootTreeItem.setGraphic(SvgIconEnum.ICON_ZK_ROOT_DEMO.init(Color.DIMGRAY, 14, 14));
            //刷新节点
            refreshZkNode(rootTreeItem);
            // 展开节点
            if (!rootTreeItem.isExpanded()) {
                rootTreeItem.setExpanded(true);
            }
            // 加载 table
            setZkInfo(ConnectionInfoCache.getConnectInfo(informationTab.getId()), rootTreeItem.getValue());

            // 连接监控，清除样式
            zkConnectionInfo.connectedProperty().addListener((obv, ov, nv) -> {
                if (!nv) {
                    rootTreeItem.getChildren().clear();
                    rootTreeItem.setValue(null);
                    rootTreeItem.setGraphic(null);
                }
            });
        }
    }


    /**
     * 刷新节点列表
     *
     * @param treeItem 当前选择的Item
     */
    public void refreshZkNode(TreeItem<ZkNodeInfo> treeItem) {
        ZkNodeInfo currentZkNode = treeItem.getValue();
        // 添加缓存
        TreeItemCache.put(currentZkNode.getId(), currentZkNode.getPath(), treeItem);
        CuratorFramework curatorZkClient = CuratorClientCache.getCuratorClient(currentZkNode.getId());
        if (CuratorZkUtil.isConnect(curatorZkClient)) {
            // 异步加载
            Platform.runLater(() -> {
                List<String> nodeList = CuratorZkUtil.getChildren(curatorZkClient, currentZkNode);
                if (currentZkNode.getStat().getNumChildren() == 0) {
                    return;
                }
                if (nodeList != null) {
                    ObservableList<TreeItem<ZkNodeInfo>> zkNodes = treeItem.getChildren();
                    zkNodes.clear();
                    nodeList.forEach(zkNode -> {
                        String path;
                        if (ZkConstant.ROOT_NODE.equals(currentZkNode.getPath())) {
                            path = currentZkNode.getPath() + zkNode;
                        } else {
                            path = currentZkNode.getPath() + ZkConstant.ROOT_NODE + zkNode;
                        }
                        ZkNodeInfo zkNodeInfo = new ZkNodeInfo(currentZkNode.getId(), path, zkNode);
                        TreeItem<ZkNodeInfo> zkNodeInfoTreeItem = new TreeItem<>();
                        zkNodeInfoTreeItem.setValue(zkNodeInfo);
                        zkNodes.add(zkNodeInfoTreeItem);
                        // 递归再次刷新
                        refreshZkNode(zkNodeInfoTreeItem);
                    });
                }
            });
        }
    }

    /**
     * 加载并设置标题
     *
     * @param connectionInfo 连接信息
     * @param zkNodeInfo     节点信息
     */
    private void setZkInfo(ZkConnectionInfo connectionInfo, ZkNodeInfo zkNodeInfo) {
        currentPathTextField.setText(zkNodeInfo.getPath());
        CuratorFramework curatorZkClient = CuratorClientCache.getCuratorClient(connectionInfo.getId());
        if (curatorZkClient != null) {
            CuratorZkUtil.getACL(curatorZkClient, zkNodeInfo);
            setAclList(zkNodeInfo);
            CuratorZkUtil.getData(curatorZkClient, zkNodeInfo);
        }
        setZkStat(zkNodeInfo);
        setZkData(zkNodeInfo);
    }

    private void setAclList(ZkNodeInfo zkNodeInfo) {
        ObservableList<String> childrenList = aclListView.getItems();
        childrenList.clear();
        for (ACL acl : zkNodeInfo.getAcl()) {
            childrenList.add(acl.toString());
        }
    }


    public void setZkStat(ZkNodeInfo zkNodeInfo) {
        if (zkNodeInfo.getPath().equals(currentPathTextField.getText())) {
            Stat stat = zkNodeInfo.getStat();
            statPzxid.setText(String.valueOf(stat.getPzxid()));
            statCzxid.setText(String.valueOf(stat.getCzxid()));
            statMzxid.setText(String.valueOf(stat.getMzxid()));
            statCtime.setText(String.valueOf(stat.getCtime()));
            statMtime.setText(String.valueOf(stat.getMtime()));
            statVersion.setText(String.valueOf(stat.getVersion()));
            statCversion.setText(String.valueOf(stat.getCversion()));
            statAversion.setText(String.valueOf(stat.getAversion()));
            statDataLength.setText(String.valueOf(stat.getDataLength()));
            statNumChildren.setText(String.valueOf(stat.getNumChildren()));
            statEphemeralOwner.setText(String.valueOf(stat.getEphemeralOwner()));
        }
    }

    public void setZkData(ZkNodeInfo zkNodeInfo) {
        if (zkNodeInfo.getPath().equals(currentPathTextField.getText())) {
            String data = null;
            if (zkNodeInfo.getData() != null) {
                data = new String(zkNodeInfo.getData(), Charset.forName(dataCharset.getSelectionModel().getSelectedItem()));
                dataCharset.getSelectionModel().selectedItemProperty().addListener((obv, ov, nv) -> {
                    if (!StringUtils.isEmpty(nv)) {
                        dataTextArea.setText(new String(zkNodeInfo.getData(), Charset.forName(nv)));
                    }
                });
            }
            dataTextArea.setText(data);
        }
    }

    /**
     * 关闭或打开除root节点外的所有节点
     *
     * @param treeItem 当前操作的item
     * @param expanded 打开或关闭
     */
    public void expandedOrCloseTree(TreeItem<ZkNodeInfo> treeItem, boolean expanded) {
        AtomicReference<TreeItem<ZkNodeInfo>> currentTreeItem = new AtomicReference<>(treeItem);
        while (!currentTreeItem.get().isLeaf()) {
            currentTreeItem.get().setExpanded(expanded);
            currentTreeItem.get().getChildren().forEach(item -> {
                item.setExpanded(expanded);
                currentTreeItem.set(item);
            });
        }
        if (!zkNodeTreeView.getRoot().equals(treeItem)) {
            zkNodeTreeView.getSelectionModel().select(treeItem);
        }
    }


    /**
     * 切换视图
     *
     * @param flag 标志 true 显示节点视图 ,false 显示搜索视图
     */
    private void switchView(boolean flag) {
        ObservableList<Node> children = treeRootVbox.getChildren();
        if (flag) {
            children.remove(searchResultListView);
            if (!children.contains(zkNodeTreeView)) {
                children.add(zkNodeTreeView);
            }
        } else {
            children.remove(zkNodeTreeView);
            if (!children.contains(searchResultListView)) {
                children.add(searchResultListView);
            }
        }
    }

    /**
     * 切换搜索结果
     *
     * @param zkNodeTreeViewModel zkNodeTreeViewSelectModel
     * @param searchResultModel   searchResultListViewSelectModel
     */
    private void switchSearchResult(MultipleSelectionModel<TreeItem<ZkNodeInfo>> zkNodeTreeViewModel, MultipleSelectionModel<TextFlow> searchResultModel) {
        TextFlow selectedTextFlow = searchResultModel.getSelectedItem();
        if (selectedTextFlow != null) {
            switchView(true);
            @SuppressWarnings("unchecked")
            TreeItem<ZkNodeInfo> selectedItem = (TreeItem<ZkNodeInfo>) selectedTextFlow.getUserData();
            zkNodeTreeViewModel.select(selectedItem);
            setZkInfo(ConnectionInfoCache.getConnectInfo(informationTab.getId()), selectedItem.getValue());
            searchField.setText(null);
        }
    }

    /**
     * 获取当前节点信息
     *
     * @return zkNodeINfo
     */
    private ZkNodeInfo getCurrentTreeItem() {
        TreeItem<ZkNodeInfo> treeItem = TreeItemCache.getTreeItem(informationTab.getId(), currentPathTextField.getText());
        if (treeItem != null) {
            return treeItem.getValue();
        }
        return null;
    }

    /**
     * 高亮文本
     *
     * @param path      路径
     * @param highlight 高亮文本
     * @return 高亮后的文本集合
     */
    private List<Text> highlightText(String path, String highlight) {
        if (highlight == null || "".equals(highlight)) {
            return Collections.emptyList();
        }
        if (path == null || "".equals(path)) {
            return Collections.emptyList();
        }
        ArrayList<Text> textArrayList = new ArrayList<>();
        String[] split = path.split(highlight);
        if (split.length == 0) {
            Text highlightText = new Text(highlight);
            highlightText.setFill(Color.RED);
            textArrayList.add(highlightText);
        } else {
            for (int i = 0; i < split.length; i++) {
                textArrayList.add(new Text(split[i]));
                if (split.length == 1 || i != split.length - 1) {
                    Text highlightText = new Text(highlight);
                    highlightText.setFill(Color.RED);
                    textArrayList.add(highlightText);
                }
            }
        }
        return textArrayList;
    }

    /**
     * 切换 JFXTextFieldStyle 状态
     *
     * @param editable 开启编辑标志
     */
    private void switchJFXTextFieldStyle(boolean editable) {
        String editableJfxTextField = "editable-jfx-text-field";
        ObservableList<String> pzxidStyleClass = statPzxid.getStyleClass();
        ObservableList<String> czxidStyleClass = statCzxid.getStyleClass();
        ObservableList<String> mzxidStyleClass = statMzxid.getStyleClass();
        ObservableList<String> ctimeStyleClass = statCtime.getStyleClass();
        ObservableList<String> mtimeStyleClass = statMtime.getStyleClass();
        ObservableList<String> versionStyleClass = statVersion.getStyleClass();
        ObservableList<String> cversionStyleClass = statCversion.getStyleClass();
        ObservableList<String> aversionStyleClass = statAversion.getStyleClass();
        ObservableList<String> dataLengthStyleClass = statDataLength.getStyleClass();
        ObservableList<String> numChildrenStyleClass = statNumChildren.getStyleClass();
        ObservableList<String> ephemeralOwnerStyleClass = statEphemeralOwner.getStyleClass();
        if (editable) {
            pzxidStyleClass.remove(editableJfxTextField);
            czxidStyleClass.remove(editableJfxTextField);
            mzxidStyleClass.remove(editableJfxTextField);
            ctimeStyleClass.remove(editableJfxTextField);
            mtimeStyleClass.remove(editableJfxTextField);
            versionStyleClass.remove(editableJfxTextField);
            cversionStyleClass.remove(editableJfxTextField);
            aversionStyleClass.remove(editableJfxTextField);
            dataLengthStyleClass.remove(editableJfxTextField);
            numChildrenStyleClass.remove(editableJfxTextField);
            ephemeralOwnerStyleClass.remove(editableJfxTextField);
        } else {
            pzxidStyleClass.add(editableJfxTextField);
            czxidStyleClass.add(editableJfxTextField);
            mzxidStyleClass.add(editableJfxTextField);
            ctimeStyleClass.add(editableJfxTextField);
            mtimeStyleClass.add(editableJfxTextField);
            versionStyleClass.add(editableJfxTextField);
            cversionStyleClass.add(editableJfxTextField);
            aversionStyleClass.add(editableJfxTextField);
            dataLengthStyleClass.add(editableJfxTextField);
            numChildrenStyleClass.add(editableJfxTextField);
            ephemeralOwnerStyleClass.add(editableJfxTextField);
        }
        statPzxid.setEditable(editable);
        statCzxid.setEditable(editable);
        statMzxid.setEditable(editable);
        statCtime.setEditable(editable);
        statMtime.setEditable(editable);
        statVersion.setEditable(editable);
        statCversion.setEditable(editable);
        statAversion.setEditable(editable);
        statDataLength.setEditable(editable);
        statNumChildren.setEditable(editable);
        statEphemeralOwner.setEditable(editable);
    }

    private void initContextMenu() {

        MenuItem refreshTab = new MenuItem("刷新");
        //分割线
        SeparatorMenuItem refreshTabSeparator = new SeparatorMenuItem();
        MenuItem closeCurrentTab = new MenuItem("关闭当前");
        MenuItem closeOtherTab = new MenuItem("关闭其他");
        MenuItem closeAllTab = new MenuItem("关闭所有");
        MenuItem closeLeftTab = new MenuItem("关闭左侧");
        MenuItem closeRightTab = new MenuItem("关闭右侧");
        refreshTab.setOnAction(event -> alertCtrl.setMessageAndShow("刷新（待开发）"));
        closeCurrentTab.setOnAction(event -> informationTableCtrl.getTabs().remove(informationTab));
        closeOtherTab.setOnAction(event -> alertCtrl.setMessageAndShow("关闭其他（待开发）"));
        closeAllTab.setOnAction(event -> alertCtrl.setMessageAndShow("关闭所有（待开发）"));
        closeLeftTab.setOnAction(event -> alertCtrl.setMessageAndShow("关闭左侧（待开发）"));
        closeRightTab.setOnAction(event -> alertCtrl.setMessageAndShow("关闭右侧（待开发）"));
        informationTab.setContextMenu(new ContextMenu(refreshTab, refreshTabSeparator, closeCurrentTab, closeOtherTab, closeAllTab, closeLeftTab, closeRightTab));
    }
}
